package com.lcy.struct.bTreePlus.disk.recovery;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.lcy.struct.bTreePlus.disk.core.BPlusTree;
import com.lcy.struct.bTreePlus.disk.log.LogUtils;
import com.lcy.struct.bTreePlus.disk.recovery.redo.NoForceDurationEngine;
import com.lcy.struct.bTreePlus.disk.recovery.redo.RedoCenter;
import com.lcy.struct.bTreePlus.disk.recovery.undo.UndoCenter;
import com.lcy.struct.bTreePlus.entity.BplusTreeTransactionInfo;
import com.lcy.struct.bTreePlus.entity.RedoInfo;

import java.util.ArrayList;
import java.util.List;

/**
 * @author lucongyang
 * @date Created in  9:51
 * @description redo.log
 */
public class RecoveryCenter {
    public ObjectMapper objectMapper = new ObjectMapper();

    /**
     * redo的加入
     *
     * @param bplusTreeTransactionInfo 需要持久化的数据
     */
    public void addToRedo(BplusTreeTransactionInfo bplusTreeTransactionInfo) {
        long transactionId = System.currentTimeMillis();
        stealNoForce(transactionId, bplusTreeTransactionInfo);
        LogUtils.log("事务id={}，commit", transactionId);
    }

    /**
     * 提交事务时steal-NoForce策略
     */
    public void stealNoForce(long transactionId, BplusTreeTransactionInfo bplusTreeTransactionInfo) {
        List<BPlusTree> transactionNeedSerializeTrees = new ArrayList<>();
        bplusTreeTransactionInfo.getNeedSerializeMap().forEach((k, v) -> transactionNeedSerializeTrees.add(v));
        RedoInfo redoInfo = new RedoInfo();
        redoInfo.setTransactionId(transactionId);
        redoInfo.setToSerializedBplusTreeList(transactionNeedSerializeTrees);
        redoInfo.setCount(bplusTreeTransactionInfo.getCount());
        redoInfo.setEndPosition(bplusTreeTransactionInfo.getEndPosition());
        redoInfo.setRootPosition(bplusTreeTransactionInfo.getRootPosition());

        RedoCenter.getInstance().writeIntoRedo(transactionId, redoInfo);
        // 非强制落盘
        NoForceDurationEngine.getInstance().join(redoInfo);
        NoForceDurationEngine.getInstance().noForceDuration();
    }

    /**
     * 故障恢复未持久化的数据
     * 一般在重启的时候调用
     */
    public void recoveryUnDuration() {
        List<RedoInfo> redoInfoList = RedoCenter.getInstance().getTransactionRedoList();
        RedoCenter.getInstance().doRedo(redoInfoList);

        RedoCenter.getInstance().clearRedo(true);

        // undo日志
        UndoCenter.getInstance().doOnReboot();
    }


    /**
     * 返回单例
     */
    public static RecoveryCenter getInstance() {
        return RecoveryCenterHandler.INSTANCE;
    }

    private static class RecoveryCenterHandler {
        private static final RecoveryCenter INSTANCE = new RecoveryCenter();
    }

    private RecoveryCenter() {
    }
}
